데이터 타입¶
수치형 데이터 타입¶
정수 또는 실수를 저장하기 위해 다음의 수치형 데이터 타입을 지원한다.
타입 | Bytes | 최소값 | 최대값 | 정확/근사치 |
---|---|---|---|---|
SHORT, SMALLINT | 2 | -32,768 | 32,767 | 정확한 수치 |
INTEGER, INT | 4 | -2,147,483,648 | +2,147,483,647 | 정확한 수치 |
BIGINT | 8 | -9,223,372,036,854,775,808 | +9,223,372,036,854,775,807 | 정확한 수치 |
NUMERIC, DECIMAL | 16 | 정밀도 p: 1 스케일 s: 0 |
정밀도 p: 38 스케일 s: 38 |
정확한 수치 |
FLOAT, REAL | 4 | -3.402823466E+38 (ANSI/IEEE 754-1985 표준) | +3.402823466E+38 (ANSI/IEEE 754-1985 표준) | 근사치 부동소수점: 7자리 |
DOUBLE, DOUBLE PRECISION | 8 | -1.7976931348623157E+308 (ANSI/IEEE 754-1985 표준) | +1.7976931348623157E+308 (ANSI/IEEE 754-1985 표준) | 근사치 부동소수점: 15자리 |
수치형 데이터 타입은 정확한(exact) 타입과 근사치(approximate) 타입으로 구분된다. 정확한 수치형 데이터 타입(SMALLINT, INT, BIGINT, NUMERIC)은 정확하고 일관된 값을 가져야 하는 경우에 사용된다. 근사치 수치형 데이터 타입(FLOAT, DOUBLE)은 리터럴 값이 같아도 시스템에 따라 다르게 해석될 수 있으므로 주의한다.
CUBRID는 수치형 데이터 타입에 대해 UNSIGNED 타입을 지원하지 않는다.
위의 표에서 두 가지 이름으로 표기한 타입들은 동일하지만, 테이블 생성 후 SHOW COLUMNS 문으로 타입의 이름을 확인할 때에는 항상 위 단어로 표기된다. 예를 들어, 테이블을 생성할 때에는 SHORT, SMALLINT 둘 다 쓸 수 있으며, SHOW COLUMNS 문으로 타입의 이름을 확인할 때에는 항상 SHORT 로 표기된다.
정밀도와 스케일(Precision and Scaling)
숫자 데이터 타입의 정밀도(precision)는 그 값이 유지할 수 있는 유효한 자릿수로 정의된다. 이는 정확한 수치형이든 근사치 수치형이든 마찬가지이다.
스케일(scale)은 소수점 이하의 자릿수를 나타내는데, 정확한 수치형에서만 의미가 있다. 정확한 수치형으로 선언된 속성은 항상 고정된 정밀도와 스케일을 갖게 된다. NUMERIC (또는 DECIMAL) 데이터 타입은 항상 최소한 한 자리의 정밀도를 갖는다. 스케일의 범위는 0과 선언된 정밀도 사이여야 한다. 스케일이 정밀도보다 클 수는 없다. INTEGER 나 SMALLINT, BIGINT 데이터 타입에서는 스케일은 0이고(즉, 소수점 이하가 없음), 정밀도는 시스템에 의해 고정된다.
수치형 리터럴(Numeric Literals)
수치형 값을 입력하기 위해서는 특별한 기호가 사용될 수 있는데, 플러스(+)는 양수를, 마이너스(-)는 음수를 나타내는 데 사용한다. 과학용 표기법이 사용될 수도 있다. 화폐 값을 표현하기 위하여 시스템에 지정된 통화 기호를 사용할 수도 있다. 수치형 리터럴로 표현 가능한 최대 정밀도는 255이다.
수치형 변환(Numeric Coercions)
모든 수치형 데이터 타입은 상호 비교 가능하고, 이를 위해 서로 공통된 수치형 데이터 타입으로 자동 변환이 이루어진다. 명시적인 변환은 CAST 연산자를 이용해야 한다. 서로 다른 수치형 데이터가 서로 정렬되거나, 수식에서 계산될 때에는 시스템에 의하여 자동으로 변환된다. 예를 들어, FLOAT 타입의 속성 값과 INTEGER 타입의 속성 값을 더하게 되면, 시스템이 자동적으로 INTEGER 속성 값을 가장 근사한 FLOAT 값으로 변환한 후 덧셈을 수행한다.
다음은 FLOAT 타입 값과 INTEGER 타입 값을 더하는 경우 FLOAT 타입 값을 출력하는 예이다.
CREATE TABLE tbl (a INT, b FLOAT); INSERT INTO tbl VALUES (10, 5.5); SELECT a + b FROM tbl;1.550000e+01
다음은 두 개의 정수 값을 더하는 경우 결과 값도 INTEGER 타입이 되기 때문에 오버플로우(overflow) 에러가 발생하는 예이다.
SELECT 100000000*1000000;
- ::
- ERROR: Data overflow on data type integer.
위와 같은 경우 어느 한 쪽의 타입을 BIGINT로 명시하면, BIGINT로 결과 값을 결정하고, 정상적인 결과를 출력한다.
SELECT CAST(100000000 AS BIGINT)*1000000;100000000000000
Warning
CUBRID 2008 R2.0 미만 버전에서는 입력된 상수가 INTEGER 범위를 넘어서면 NUMERIC으로 처리되었으나, CUBRID 2008 R2.0 이상 버전에서는 BIGINT로 처리된다.
INT, INTEGER¶
INTEGER 데이터 타입은 정수 표현을 위해 사용하며, 표현할 수 있는 값의 범위는 -2,147,483,648에서 +2,147,483,647이다. 작은 정수를 표현하기 위해 SMALLINT를 사용하거나, 큰 정수를 표현하기 위해 BIGINT를 사용할 수 있다.
- INTEGER와 INT는 같은 의미로 사용된다.
- INT 타입에 실수가 입력되면, 소수점 아래 숫자가 반올림되어 정수값이 저장된다.
- 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.
INTEGER에 8934를 지정하면 8934가 저장됨.
INTEGER에 7823467를 지정하면 7823467이 저장됨.
INTEGER에 89.8를 지정하면 90이 저장됨(소수점 뒤의 수치는 반올림됨).
INTEGER에 3458901122를 지정하면 오류가 발생함(표현 가능 범위를 초과하면 오류 발생).
SHORT, SMALLINT¶
SMALLINT 데이터 타입은 작은 정수 표현을 위해 사용되며, 표현할 수 있는 값의 범위는 -32,768에서 +32,767이다.
- SMALLINT와 SHORT는 같은 의미로 사용된다.
- SMALLINT 타입에 실수가 입력되면, 소수점 아래 숫자가 반올림되어 정수값이 저장된다.
- 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.
SMALLINT에 8934를 지정하면 8934가 저장됨.
SMALLINT에 34.5를 지정하면 35가 저장됨(소수점 이하의 숫자는 반올림됨).
SMALLINT에 23467를 지정하면 23467이 저장됨.
SMALLINT에 89354를 지정하면 오류가 발생함(표현 가능 범위를 초과하면 오류 발생).
BIGINT¶
BIGINT 데이터 타입은 큰 정수 표현을 위해 사용되며, 표현할 수 있는 값의 범위는 -9,223,372,036,854,775,808에서 9,223,372,036,854,775,807이다.
BIGINT 타입에 실수가 입력되면, 소수점 아래 숫자가 반올림되어 정수값이 저장된다.
정밀도와 표현할 수 있는 범위를 기준으로는 다음과 같이 정렬할 수 있다.
SMALLINT ⊂ INTEGER ⊂ BIGINT ⊂ NUMERIC
이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.
BIGINT에 8934를 지정하면 8934가 저장됨.
BIGINT에 89.1을 지정하면 89가 저장됨.
BIGINT에 89.8을 지정하면 90이 저장됨(소수점 뒤의 수치는 반올림됨).
BIGINT에 3458901122를 지정하면 3458901122가 저장됨.
NUMERIC, DECIMAL¶
NUMERIC 또는 DECIMAL 데이터 타입은 고정 소수점 숫자를 표현하기 위해 사용되며, 다음과 같이 전체 자리 수(정밀도)와 소수점 아래 자릿수(스케일)을 옵션으로 지정하여 정의할 수 있다. 정밀도 p의 최소값은 1이고 최대값은 38이며, 정밀도 p가 생략되면 기본값은 15이므로, 정수부가 15자리를 초과하는 데이터를 입력할 수 없다. 또한, 스케일 s가 생략되면 스케일의 기본값은 0이므로 소수점 아래 첫째 자리에서 반올림한 정수를 반환한다.
NUMERIC [(p[, s])]
- 정밀도는 반드시 스케일 이상이어야 한다.
- 정밀도는 (데이터의 정수부 자리 수 + 스케일) 이상이 되도록 지정한다.
- NUMERIC과 DECIMAL, 그리고 DEC는 같은 의미로 사용된다.
- NUMERIC 타입끼리 연산한 결과 값의 정밀도와 스케일이 어떻게 달라지는지 확인하려면 수치형 데이터 타입의 산술 연산과 타입 변환을 참고한다.
- 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.
NUMERIC에 12345.6789를 지정하면 12346이 저장됨(스케일 기본값은 0이므로 소수점 아래 첫째 자리에서 반올림함).
NUMERIC(4)에 12345.6789를 지정하면 오류가 발생함(정밀도는 데이터의 정수부 자릿수 이상이어야 함).
NUMERIC(3,4)를 선언하면 오류가 발생함(정밀도는 스케일 이상이어야 함).
NUMERIC(4,4)에 0.123456789를 지정하면 .1235가 저장됨(소수점 아래 다섯째 자리에서 반올림함).
NUMERIC(4,4)에 -0.123456789를 지정하면 -.1235가 저장됨(소수점 아래 다섯째 자리에서 반올림한 후, - 부호를 붙임).
FLOAT, REAL¶
FLOAT (또는 REAL) 데이터 타입은 부동 소수점 숫자를 표현하기 위해 사용된다.
정규 값(normalized value)으로 표현할 수 있는 값의 범위는 -3.402823466E+38 에서 -1.175494351E-38, 0, 그리고 +1.175494351E-38 에서+3.402823466E+38이며, 이 범위를 벗어나서 0에 가까운 값은 비정규 값(denormalized value)으로 표현한다. 이는 ANSI/IEEE 754-1985 표준을 준수한다.
정밀도 p의 최소값은 1이고 최대값은 38이며, 정밀도 p가 생략되거나 7 이하로 지정되면 단일 정밀도(single-precision, 7자리의 유효 숫자)로 표현된다. 만약 정밀도 p가 7보다 크고 38 이하이면 이중 정밀도(double-precision, 15자리의 유효 숫자)로 표현되며, DOUBLE 데이터 타입으로 변환된다.
FLOAT 데이터 타입은 7자리의 유효 자릿수를 넘는 입력 값에 대해 근사치를 저장하는 타입이므로 유효 자릿수를 넘어서는 정확한 값을 저장하려면 사용하지 않도록 주의한다.
FLOAT[(p)]
- FLOAT 타입의 유효 자리 수는 7이다.
- FLOAT 타입은 근사치 데이터를 저장하므로 데이터 비교 시 주의해야 한다.
- FLOAT와 REAL은 같은 의미로 사용된다.
- 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.
FLOAT에 16777217을 입력하면 16777216이 저장되고, 1.677722e+07이 출력된다(정밀도가 생략되면, 7개의 유효 숫자로 표현하므로 8번째 숫자를 반올림함).
FLOAT(5)에 16777217을 입력하면 16777216이 저장되고, 1.677722e+07이 출력된다(정밀도가 7 이하이면, 7개의 유효 숫자로 표현하므로 8번째 숫자를 반올림함).
FLOAT(5)에 16777.217을 입력하면 16777.216이 저장되고, 1.677722e+04가 출력된다(정밀도가 7 이하이면, 7개의 유효 숫자로 표현하므로 8번째 숫자를 반올림함).
FLOAT(10)에 16777.217를 지정하면 16777.217이 저장되고, 1.677721700000000e+04가 출력된다(정밀도가 7보다 크고 38 이하이면, DOUBLE 타입으로 변환되어 15개의 유효 숫자로 표현하므로 0을 채움).
DOUBLE, DOUBLE PRECISION¶
DOUBLE 데이터 타입은 부동 소수점 숫자를 표현하기 위해 사용된다.
정규 값(normalized value)으로 표현할 수 있는 값의 범위는 -1.7976931348623157E+308에서 -2.2250738585072014E-308, 0, 그리고 2.2250738585072014E-308에서 1.7976931348623157E+308이며, 이 범위를 벗어나서 0에 가까운 값은 비정규 값(denormalized value)으로 표현한다. 이는 ANSI/IEEE 754-1985 표준을 준수한다.
정밀도를 지정할 수 없으며, 이 타입이 지정된 데이터는 이중 정밀도(double-precision, 15자리의 유효 숫자)로 표현된다.
DOUBLE 데이터 타입은 15자리의 유효 자릿수를 넘는 입력 값에 대해 근사치를 저장하는 타입이므로 유효 자릿수를 넘어서는 정확한 값을 지정할 때에는 사용하지 않도록 주의한다.
- DOUBLE의 유효 자리 수는 15자리이다.
- DOUBLE 타입은 근사치 데이터를 저장하므로 데이터 비교 시 주의해야 한다.
- DOUBLE과 DOUBLE PRECISION은 같은 의미로 사용된다.
- 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.
DOUBLE에 1234.56789를 입력하면 1234.56789가 저장되고, 1.234567890000000e+03이 출력된다.
DOUBLE에 9007199254740993을 입력하면 9007199254740992가 저장되고, 9.007199254740992e+15가 출력된다.
Note
MONETARY 타입은 제거될 예정이며(deprecated), 더 이상 사용을 권장하지 않는다.
날짜/시간 데이터 타입¶
날짜/시간 데이터 타입은 날짜, 시간 혹은 이 두 가지를 모두 표현할 때 사용하는 데이터 타입으로 다음과 같은 데이터 타입을 지원한다.
타입 | bytes | 최소값 | 최대값 | 비고 |
---|---|---|---|---|
DATE | 4 | 0001년 1월 1일 | 9999년 12월 31일 | 예외적으로 DATE '0000-00-00'을 입력할 수 있다. |
TIME | 4 | 00시 00분 00초 | 23시 59분 59초 | |
TIMESTAMP | 4 | 1970년 1월 1일 0시 0분 1초(GMT) 1970년 1월 1일 9시 0분 1초(KST) | 2038년 1월 19일 3시 14분 7초(GMT) 2038년 1월 19일 12시 14분 7초(KST) | 예외적으로 TIMESTAMP '0000-00-00 00:00:00'을 입력할 수 있다. |
DATETIME | 8 | 0001년 1월 1일 0시 0분 0.000초 | 9999년 12월 31일 23시 59분 59.999초 | 예외적으로 DATETIME '0000-00-00 00:00:00'을 입력할 수 있다. |
범위와 해상도(Range and Resolution)
- 시간 값의 표현은 기본적으로 24시간 시스템에 의하여 그 범위가 결정된다. 날짜는 그레고리력(Gregorian calendar)을 따른다. 이 두 제약 사항을 벗어나는 값이 날짜나 시간으로 입력되면 오류가 발생한다.
- DATE 중 연도의 범위는 0001~9999 AD이다.
- CUBRID 2008 R3.0 버전부터는 연도를 두 자리만 표기하면, 00~69는 2000~2069로 변환되고, 70~99는 1970~1999로 변환된다. R3.0 미만 버전에서는 01~99까지의 두 자리 연도를 표기하면, 각각 0001~0099로 변환된다.
- TIMESTAMP 의 범위는 GMT로 1970년 1월 1일 0시 0분 1초부터 2038년 1월 19일 03시 14분 07초까지이다. KST (GMT+9)로는 1970년 1월 1일 9시 0분 1초부터 2038년 1월 19일 12시 14분 07초까지 저장할 수 있다. GMT로 timestamp'1970-01-01 00:00:00'은 timestamp'0000-00-00 00:00:00'와 같다.
- 날짜, 시간, 타임스탬프와 관련된 연산은 시스템의 반올림 시스템에 따라 결과가 달라질 수 있다. 이러한 경우, 시간과 타임스탬프는 가장 근접한 초를 최소 해상도로, 날짜는 가장 근접한 날짜를 최소 해상도로 하여 결정된다.
변환(Coercion)
날짜/시간 데이터 타입의 값은 서로 똑같은 항목을 가지고 있는 경우에만 CAST 연산자를 이용한 명시적인 변환이 가능하며, 묵시적 변환은 묵시적 타입 변환 을 참고한다. 아래의 표는 명시적 변환이 가능한 타입을 설명한다. 날짜/시간 데이터 타입 간 산술 연산에 대한 내용은 날짜/시간 데이터 타입의 산술 연산과 타입 변환 을 참고한다.
명시적 변환
FROM \ TO DATE TIME DATETIME TIMESTAMP DATE - X O O TIME X - X X DATETIME O O - O TIMESTAMP O O O -
DATE, DATETIME, TIMESTAMP 타입의 연, 월, 일에는 0을 입력할 수 없으나, 예외적으로 날짜와 시간이 모두 0인 값은 허용한다. 해당 타입의 칼럼에 대한 질의 수행 시 인덱스가 있으면 이 값을 사용할 수 있다는 점에서 NULL 대신 사용하면 유용하다.
- DATE, DATETIME, TIMESTAMP 타입이 인자인 일부 함수는 인자의 날짜와 시간 값이 모두 0이면 시스템 파라미터 return_null_on_function_errors 의 값에 따라 다른 값을 반환한다. return_null_on_function_errors 가 yes이면 NULL 을 반환하고 no이면 에러를 반환하며, 기본값은 no 이다.
- DATE, DATETIME, TIMESTAMP 타입을 반환하는 함수들은 날짜와 시간 값이 모두 0인 값을 반환할 수 있지만 JAVA 응용 프로그램에서는 이러한 값을 Date 객체에 저장할 수 없다. 따라서 연결 URL 문자열의 zeroDateTimeBehavior 속성(Property) 설정에 따라서 예외로 처리하거나 NULL을 반환하거나 또는 최소값을 반환한다(이에 관한 자세한 내용은 연결 설정 참고).
- 시스템 파라미터 intl_date_lang을 설정하면
TO_DATE()
,TO_DATETIME()
,TO_TIMESTAMP()
함수의 입력 문자열 형식이 해당 로캘의 날짜 형식을 따른다. 자세한 내용은 구문/타입 관련 파라미터과 각 함수의 설명을 참고한다.
DATE¶
DATE 데이터 타입은 연도(yyyy), 월(mm), 일(dd)을 표현하며, 지원 범위는 '01/01/0001'에서 '12/31/9999'까지이다. 연도는 생략 가능하며, 생략될 경우 현재 시스템의 연도 값이 자동으로 지정된다. 입력 형식은 다음과 같다.
date'mm/dd[/yyyy]'
date'[yyyy-]mm-dd'
- 모든 항목은 정수 형태로 입력되어야 한다.
- CSQL은 'MM/DD/YYYY' 형식으로 날짜 값을 출력하고, JDBC 응용 프로그램 및 CUBRID 매니저는 'YYYY-MM-DD' 형식으로 날짜 값을 출력한다.
- 문자열 타입의 데이터를 DATE 타입으로 변환하는 함수는
TO_DATE()
이다. - 연, 월, 일에는 0을 입력할 수 없으나 예외적으로 연, 월, 일이 모두 0인 '0000-00-00'은 입력할 수 있다.
- 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.
DATE'2008-10-31'은 '10/31/2008'로 출력된다.
DATE'10/31'은 '10/31/2011'으로 출력된다(연도가 생략되면 현재 연도가 자동으로 지정됨).
DATE'00-10-31'은 '10/31/2000'로 출력된다.
DATE'0000-10-31'은 에러가 출력된다(연도의 최소값은 1).
DATE'70-10-31'은 '10/31/1970'로 출력된다.
DATE'0070-10-31'은 '10/31/0070'로 출력된다.
TIME¶
TIME 데이터 타입은 시각(hh), 분(mi), 초(ss) 를 표현하며, 지원 범위는 ’00:00:00’에서 ’23:59:59’까지이다. 초는 생략 가능하며, 생략될 경우 0초로 지정된다. 입력 형식은 12시간 표기법(AM/PM표기법) 또는 24시간 표기법이 모두 허용되며, 다음과 같이 작성한다.
time'hh:mi[:ss] [am | pm]'
- 모든 항목은 정수로 입력되어야 한다.
- CSQL은 항상 AM/PM 표기법으로 시간 값을 출력하고, JDBC 응용 프로그램 및 CUBRID 매니저는 24시간 표기법으로 시간 값을 출력한다.
- 24시간 표기법으로 시간 값을 입력할 때에도 AM/PM을 지정할 수 있으며, 이때 시간 값과 지정된 AM 또는 PM이 일치하지 않으면 오류가 발생한다.
- 모든 시간 값은 데이터베이스에는 24시간 표기법으로 저장된다.
- 문자열 타입의 데이터를 TIME 타입으로 변환하는 함수는
TO_TIME()
이다. - 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.
TIME'00:00:00'은 '12:00:00 AM'으로 출력된다.
TIME'1:15'는 '01:15:00 AM'으로 간주된다.
TIME'13:15:45'는 '01:15:45 PM'으로 간주된다.
TIME'13:15:45 pm'은 정상적으로 저장된다.
TIME'13:15:45 am'은 오류가 발생한다(주어진 시간 값과 AM/PM이 불일치).
TIMESTAMP¶
TIMESTAMP 데이터 타입은 날짜(연, 월, 일)와 시간(시, 분, 초)을 결합한 데이터 값을 표현하며, GMT로 '1970-01-01 00:00:01'부터 '2038-01-19 03:14:07'까지 표현할 수 있다. 이 범위를 초과하거나 밀리초 단위의 시간 데이터를 저장하는 경우라면, DATETIME 데이터 타입을 이용할 수 있다. TIMESTAMP 데이터 타입의 입력 형식은 다음과 같다.
timestamp'hh:mi[:ss] [am|pm] mm/dd[/yyyy]'
timestamp'hh:mi[:ss] [am|pm] [yyyy-]mm-dd'
timestamp'mm/dd[/yyyy] hh:mi[:ss] [am|pm]'
timestamp'[yyyy-]mm-dd hh:mi[:ss] [am|pm]'
- 모든 항목은 정수로 입력되어야 한다.
- 연도를 생략하면 기본값으로 현재 연도가 지정되고, 시간 값(시/분/초)를 생략하면 12:00:00 AM으로 지정된다.
- 시스템의 현재 타임스탬프 값은
SYS_TIMESTAMP
(또는SYSTIMESTAMP
,CURRENT_TIMESTAMP
) 함수를 이용하여 TIMESTAMP 데이터 타입에 저장할 수 있다. TIMESTAMP()
함수 또는TO_TIMESTAMP()
함수를 사용하면, 문자열 데이터 타입의 데이터를 TIMESTAMP 데이터 타입으로 변환할 수 있다.- 연, 월, 일에는 0을 입력할 수 없으나 예외적으로 연, 월, 일, 시, 분, 초가 모두 0인 '0000-00-00 00:00:00'은 입력할 수 있다. GMT timestamp'1970-01-01 12:00:00 AM' 또는 KST timestamp'1970-01-01 09:00:00 AM'은 timestamp'0000-00-00 00:00:00'으로 해석된다.
- 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.
TIMESTAMP'10/31'은 '12:00:00 AM 10/31/2011'으로 출력된다(연도/시간이 생략될 경우, 기본값으로 출력).
TIMESTAMP'10/31/2008'은 '12:00:00 AM 10/31/2008'로 출력된다(시간이 생략될 경우, 기본값으로 출력).
TIMESTAMP'13:15:45 10/31/2008'은 '01:15:45 PM 10/31/2008'로 출력된다.
TIMESTAMP'01:15:45 PM 2008-10-31'은 '01:15:45 PM 10/31/2008'로 출력된다.
TIMESTAMP'13:15:45 2008-10-31'은 '01:15:45 PM 10/31/2008'로 출력된다.
TIMESTAMP'10/31/2008 01:15:45 PM'은 '01:15:45 PM 10/31/2008'로 출력된다.
TIMESTAMP'10/31/2008 13:15:45'는 '01:15:45 PM 10/31/2008'로 출력된다.
TIMESTAMP'2008-10-31 01:15:45 PM'은 '01:15:45 PM 10/31/2008'로 출력된다.
TIMESTAMP'2008-10-31 13:15:45'는 '01:15:45 PM 10/31/2008'로 출력된다.
TIMESTAMP'2099-10-31 01:15:45 PM'은 오류가 발생한다(TIMESTAMP 표현 가능 범위 초과).
DATETIME¶
DATETIME 타입은 날짜(년, 월, 일)와 시간(시, 분, 초, 밀리초)을 결합한 데이터 값을 표현하며, GMT로 0001-01-01 00:00:00.000부터 9999-12-31 23:59:59.999까지 표현할 수 있다. DATETIME 타입 데이터의 입력 형식은 다음과 같다.
datetime'hh:mi[:ss[.msec]] [am|pm] mm/dd[/yyyy]'
datetime'hh:mi[:ss[.msec]] [am|pm] [yyyy-]mm-dd'
datetime'mm/dd[/yyyy] hh:mi[:ss[.ff]] [am|pm]'
datetime'[yyyy-]mm-dd hh:mi[:ss[.ff]] [am|pm]'
- 모든 항목은 정수로 입력되어야 한다.
- 연도를 생략하면 기본값으로 현재 연도가 지정되고, 시간 값(시/분/초/밀리초)를 생략하면 12:00:00.000 AM으로 지정된다.
- 시스템의 현재 타임스탬프 값은
SYS_DATETIME
(또는SYSDATETIME
,CURRENT_DATETIME
,CURRENT_DATETIME()
,NOW()
)를 이용하여 DATETIME 타입에 저장할 수 있다. - 문자열 타입의 데이터를 DATETIME 타입으로 변환하는 함수는
TO_DATETIME()
이다. - 연, 월, 일에는 0을 입력할 수 없으나 예외적으로 연, 월, 일, 시, 분, 초가 모두 0인 '0000-00-00 00:00:00'은 입력할 수 있다.
- 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.
DATETIME'10/31'은 '12:00:00.000 AM 10/31/2011'으로 출력된다(연도/시간이 생략될 경우, 기본값으로 출력).
DATETIME'10/31/2008'은 '12:00:00.000 AM 10/31/2008'로 출력된다.
DATETIME'13:15:45 10/31/2008'은 '01:15:45.000 PM 10/31/2008'로 출력된다.
DATETIME'01:15:45 PM 2008-10-31'은 '01:15:45.000 PM 10/31/2008'로 출력된다.
DATETIME'13:15:45 2008-10-31'은 '01:15:45.000 PM 10/31/2008'로 출력된다.
DATETIME'10/31/2008 01:15:45 PM'은 '01:15:45.000 PM 10/31/2008'로 출력된다.
DATETIME'10/31/2008 13:15:45'는 '01:15:45.000 PM 10/31/2008'로 출력된다.
DATETIME'2008-10-31 01:15:45 PM'은 '01:15:45.000 PM 10/31/2008'로 출력된다.
DATETIME'2008-10-31 13:15:45'는 '01:15:45.000 PM 10/31/2008'로 출력된다.
DATETIME'2099-10-31 01:15:45 PM'은 '01:15:45.000 PM 10/31/2099'로 출력된다.
문자열을 날짜/시간 타입으로 CAST¶
날짜/시간 타입 문자열 권장 형식¶
CAST()
연산자를 사용하여 문자열을 날짜/시간 타입으로 변환할 때에는 문자열을 다음과 같은 형식으로 작성하는 것을 권장한다.
DATE 타입
YYYY-MM-DD MM/DD/YYYY
TIME 타입
HH:MI:SS [AM|PM]
DATETIME 타입
YYYY-MM-DD HH:MI:SS[.msec] [AM|PM]
TIMESTAMP 타입
YYYY-MM-DD HH:MI:SS [AM|PM]
날짜/시간 타입 문자열 허용 형식¶
DATE 문자열 허용 형식
[year sep] month sep day
- 2011-04-20 : 2011년 4월 20일
- 04-20 : 올해 4월 20일
구분자(sep)가 빗금(/)일 때에는 다음과 같은 순서로 인식한다.
month/day[/year]
- 04/20/2011 : 2011년 4월 20일
- 04/20 : 올해 4월 20일
구분자(sep)를 사용하지 않을 때에는 다음과 같은 형식으로 인식한다. 연도는 한 자리, 두 자리, 네 자리를 허용하고, 월은 한 자리, 두 자리를 허용한다. 일은 항상 두 자리를 입력해야 한다.
YYYYMMDD YYMMDD YMMDD MMDD MDD
- 20110420 : 2011년 4월 20일
- 110420 : 2011년 4월 20일
- 420 : 올해 4월 20일
TIME 문자열 허용 형식
[hour]:min[:[sec]][.[msec]] [am|pm]
- 09:10:15.359 am : 오전 9시 10분 15초(0.359초는 버림)
- 09:10:15 : 오전 9시 10분 15초
- 09:10 : 오전 9시 10분
- :10 : 오전 12시 10분
[[[[[[Y]Y]Y]Y]M]MDD]HHMISS[.[msec]] [am|pm]
- 20110420091015.359 am : 오전 9시 10분 15초
- 0420091015 : 오전 9시 10분 15초
[H]HMMSS[.[msec]] [am|pm]
- 091015.359 am : 오전 9시 10분 15초
- 91015 : 오전 9시 10분 15초
[M]MSS[.[msec]] [am|pm]
- 1015.359 am : 오전 12시 10분 15초
- 1015 : 오전 12시 10분 15초
[S]S[.[msec]] [am|pm]
- 15.359 am : 오전 12시 0분 15초
- 15 : 오전 12시 0분 15초
Note
CUBRID 2008 R3.1 이하 버전에서는 [H]H 형식을 허용했다. 즉 R3.1 이하 버전에서 문자열 '10'은 TIME'10:00:00'으로 변환되었으나, R4.0부터는 TIME'00:00:10' 으로 변환된다.
DATETIME 문자열 허용 형식
[year sep] month sep day [sep] [sep] hour [sep min[sep sec[.[msec]]]]
- 04-20 09 : 올해 4월 20일 오전 9시
month/day[/year] [sep] hour [sep min [sep sec[.[msec]]]]
- 04/20 09 : 올해 4월 20일 오전 9시
year sep month sep day sep hour [sep min[sep sec[.[msec]]]]
- 2011-04-20 09 : 2011년 4월 20일 오전 9시
month/day/year sep hour [sep min[sep sec [.[msec]]]]
- 04/20/2011 09 : 2011년 4월 20일 오전 9시
YYMMDDH (시간이 한 자리 수일 때에만 허용)
- 1104209 : 2011년 4월 20일 오전 9시
YYMMDDHHMI[SS[.msec]]
- 1104200910.359 : 2011년 4월 20일 오전 9시 10분(0.359초는 버림)
- 110420091000.359 : 2011년 4월 20일 오전 9시 10분 0.359초
YYYYMMDDHHMISS[.msec]
- 201104200910.359 : 2020년 11월 4일 오후 8시 9분 10.359초
- 20110420091000.359 : 2011년 4월 20일 오전 9시 10분 0.359초
시간-날짜 순서의 문자열 허용 형식
[hour]:min[:sec[.msec]] [am|pm] [year-]month-day
- 09:10:15.359 am 2011-04-20 : 2011년 4월 20일 오전 9시 10분 15.359초
- :10 04-20 : 올해 4월 20일 오전 12시 10분
[hour]:min[:sec[.msec]] [am|pm] month/day[/[year]]
- 09:10:15.359 am 04/20/2011 : 2011년 4월 20일 오전 9시 10분 15.359초
- :10 04/20 : 올해 4월 20일 오전 12시 10분
hour[:min[:sec[.[msec]]]] [am|pm] [year-]month-day
- 09:10:15.359 am 04-20 : 올해 4월 20일 오전 9시 10분 15.359초
- 09 04-20 : 올해 4월 20일 오전 9시
hour[:min[:sec[.[msec]]]] [am|pm] month/day[/[year]]
- 09:10:15.359 am 04/20 : 올해 4월 20일 오전 9시 10분 15.359초
- 09 04/20 : 올해 4월 20일 오전 9시
규칙
msec 은 밀리초를 나타내는 일련의 숫자이다. 앞에서 네 번째 자리부터 이후의 숫자는 무시된다. 값 사이를 구분하는 구분자의 규칙은 다음과 같다.
- TIME 문자열은 시간 구분자로 항상 하나의 콜론(:)을 사용해야 한다.
- DATE 와 DATETIME 문자열은 구분자 없이 연속된 숫자로 나타낼 수 있고, DATETIME 문자열은 시간과 날짜를 공백으로 구분할 수 있다.
- 입력 문자열 안에서 구분자들은 동일해야 한다.
- 시간-날짜 순서의 문자열은 시간 구분자로 콜론(:)만 사용할 수 있으며, 날짜 구분자로는 하이픈(-)이나 빗금(/)만 사용할 수 있다. 날짜 입력 시 하이픈을 사용하는 경우 yyyy-mm-dd 순으로 입력하며, 빗금(/)을 사용하는 경우 mm/dd/yyyy 순으로 입력한다.
날짜 부분의 문자열에는 다음 규칙이 적용된다.
- 연도는 구문이 허용하는 한 생략할 수 있다.
- 연도를 두 자리로 입력하면 1970년~2069년 범위의 연도를 나타낸다. 즉, YY<70 이면 2000+YY으로 처리하고, YY>=70이면 1900+YY으로 처리한다. 한 자리나 세 자리, 네 자리 숫자로 연도를 입력하면 해당 숫자 그대로를 나타낸다.
- 문자열 앞뒤의 공백과 뒤의 문자열은 무시된다. DATETIME, TIME 문자열을 위한 am/pm 지정자는 시간 값의 일부로 인식하지만, 공백이 아닌 문자가 뒤에 붙으면 am/pm 지정자로 인식되지 않는다.
CUBRID의 TIMESTAMP 타입은 DATE 타입과 TIME 타입으로 구성되고, DATETIME 타입은 DATE 타입과 TIME 타입에 밀리초(milliseconds)가 더해져서 구성된다. 입력 문자열은 날짜(DATE 문자열), 시간(TIME 문자열), 혹은 둘 다(DATETIME 문자열) 포함할 수 있다. 특정 타입의 데이터를 보유한 문자열은 다른 타입으로도 변환될 수 있으며 다음과 같은 규칙이 적용된다.
- DATE 문자열을 DATETIME 타입으로 변환하면 시간 값은 '00:00:00'이 된다.
- TIME 문자열을 DATETIME 타입으로 변환하면 콜론(:)이 날짜 구분자로 인식되어 TIME 문자열이 날짜를 나타내는 문자열로 인식되고, 시간 값은 '00:00:00'이 된다.
- DATETIME 문자열을 DATE 타입으로 변환하면 결과값에서 시간 부분은 무시되지만, 시간 입력값의 형식은 유효해야 한다.
- DATETIME 문자열을 TIME 타입으로 변환할 수 있지만, 다음과 같은 규칙이 적용된다.
- 문자열에 있는 날짜와 시간은 최소한 하나의 공백에 의해 구분되어야 한다.
- 결과값에서 날짜 부분은 무시되지만, 날짜 입력값의 형식이 유효해야 한다.
- 날짜 부분의 연도가 4자리 이상이거나(0으로 시작할 수 있음), 시간 부분이 최소한 시와 분([H]H:[M]M)을 포함해야 한다. 그렇지 않으면 날짜 부분이 [MM]SS 포맷의 TIME 타입으로 인식되고, 뒤이어 나오는 문자열은 무시된다.
- DATETIME 문자열의 각 단위(년, 월, 일, 시, 분, 초) 중 하나가 999999보다 크면, 숫자가 아닌 것으로 인식하여 해당 단위가 포함된 문자열이 무시된다. 예를 들어 '2009-10-21 20:9943:10'은 분 단위의 값이 범위를 벗어나므로 에러가 발생한다. 그러나 '2009-10-21 20:1000123:10'이 입력되면 '2009'를 MMSS 포맷의 TIME 타입으로 인식하여 TIME'00:20:09'를 반환한다.
- 시간-날짜 순서의 문자열을 TIME 타입으로 변환하면 문자열의 날짜 부분은 무시되지만, 날짜 부분의 형식은 유효해야 한다.
- 시간 부분이 있는 모든 입력 문자열은 변환 시 [msec] 을 허용하지만, DATETIME 타입만 그 값을 유지한다. DATE, TIMESTAMP, TIME 와 같은 타입으로 변환하면 msec 값을 버린다.
- DATETIME, TIME 문자열에서의 모든 변환은 시간 값 뒤에 나오는 영문 로캘(locale) 또는 서버의 현재 로캘로 쓰여진 am/pm 지정자를 허용한다.
SELECT CAST('420' AS DATE);cast('420' as date) ====================== 04/20/2012SELECT CAST('91015' AS TIME);cast('91015' as time) ======================== 09:10:15 AMSELECT CAST('110420091035.359' AS DATETIME);cast('110420091035.359' as datetime) ======================================= 09:10:35.359 AM 04/20/2011SELECT CAST('110420091035.359' AS TIMESTAMP);cast('110420091035.359' as timestamp) ======================================== 09:10:35 AM 04/20/2011
비트열 데이터 타입¶
비트열은 0과 1로 이루어진 이진 값의 순열(sequence)이다. CUBRID는 두 가지 비트열을 지원한다.
- 고정길이 비트열(BIT)
- 가변길이 비트열(BIT VARYING)
메서드의 인자나 속성의 타입으로 비트열을 사용할 수 있으며, 비트열 리터럴은 2진수 형식이나 16진수 형식을 사용한다. 2진수 형식으로 사용할 때에는 다음과 같이 문자 B 뒤에 0과 1로 이루어진 문자열을 붙이거나, 0b 뒤에 값을 붙여 표현한다.
B'1010'
0b1010
16진수 형식은 대문자 X 뒤에 0-9 그리고 A-F 문자로 이루어진 문자열을 붙이거나 0x 뒤에 값을 붙여 표현한다. 예를 들어, 아래는 앞에서 2진수로 표현한 것과 같은 값을 16진수로 나타낸 것이다.
X'a'
0xA
16진수에서 사용되는 문자는 대소문자를 구분하지 않는다. 즉, X'4f'와 X'4F'는 같은 값으로 간주한다.
길이(Length)
비트열이 테이블 속성이나 메서드 선언에 사용될 때에는 최대 길이를 표시해야 한다. 비트열이 가질 수 있는 최대 길이는 1,073,741,823비트이다.
비트열의 변환(Bit String Coercion)
고정길이와 가변길이 비트열 간에는 서로 비교를 위하여 자동 변환이 이루어진다. 명시적인 변환은 CAST 연산자를 이용해야 한다.
BIT(n)¶
고정길이 2진수 혹은 16진수 비트열은 BIT (n)로 나타내는데, 여기서 n 은 최대 비트의 개수를 나타낸다. 만약, n 이 생략되면 길이는 1로 지정된다. 비트열은 8비트 단위로 왼쪽부터 값이 채워진다. 예를 들어, B'1'의 값은 B'10000000'과 같은 값으로 출력된다. 따라서, 8비트 단위로 길이를 선언하고 8비트 단위로 값을 입력할 것을 권장한다.
Note
BIT(4)로 선언된 칼럼에 B'1'을 INSERT하면 CSQL에서는 X'8'로 출력되고, CUBRID Manager에서는 X'80'으로 출력된다.
- n 은 0보다 큰 숫자여야 한다.
- 비트열의 크기가 n 을 넘어설 경우에는 절삭되고, 0으로 채워진다.
- n 보다 작은 비트열이 저장될 때에는 나머지 오른쪽 부분이 0으로 채워진다.
- 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.
CREATE TABLE bit_tbl(a1 BIT, a2 BIT(1), a3 BIT(8), a4 BIT VARYING);
INSERT INTO bit_tbl VALUES (B'1', B'1', B'1', B'1');
INSERT INTO bit_tbl VALUES (0b1, 0b1, 0b1, 0b1);
INSERT INTO bit_tbl(a3,a4) VALUES (B'1010', B'1010');
INSERT INTO bit_tbl(a3,a4) VALUES (0xaa, 0xaa);
SELECT * FROM bit_tbl;
a1 a2 a3 a4
=========================================================================
X'8' X'8' X'80' X'8'
X'8' X'8' X'80' X'8'
NULL NULL X'a0' X'a'
NULL NULL X'aa' X'aa'
BIT VARYING(n)¶
가변길이 비트열은 BIT VARYING (n)으로 나타낸다. 여기서 n 은 최대 비트의 개수를 나타낸다. 만약, n 이 생략되면 최대 길이인 1,073,741,823으로 지정된다. 비트열은 8비트 단위로 왼쪽부터 값이 채워진다. 예를 들어, B'1'의 값을 입력하면 B'10000000'과 같은 값으로 출력된다. 따라서, 8비트 단위로 크기를 선언하고 8비트 단위로 값을 입력할 것을 권장한다.
Note
BIT VARYING(4)로 선언된 칼럼에 B'1'을 INSERT하면 CSQL에서는 X'8'로 출력되고, CUBRID Manager, Query Browser, 또는 응용 프로그램에서는 X'80'으로 출력된다.
- 비트열의 크기가 n 을 넘어설 경우에는 절삭되고 0으로 채워진다.
- n 보다 작은 비트열이 저장될 때에도 나머지 부분이 0으로 채워지지 않는다.
- n 은 0보다 큰 숫자여야 한다.
- 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.
CREATE TABLE bitvar_tbl(a1 BIT VARYING, a2 BIT VARYING(8));
INSERT INTO bitvar_tbl VALUES (B'1', B'1');
INSERT INTO bitvar_tbl VALUES (0b1010, 0b1010);
INSERT INTO bitvar_tbl VALUES (0xaa, 0xaa);
INSERT INTO bitvar_tbl(a1) VALUES (0xaaa);
SELECT * FROM bitvar_tbl;
a1 a2
============================================
X'8' X'8'
X'a' X'a'
X'aa' X'aa'
X'aaa' NULL
INSERT INTO bitvar_tbl(a2) VALUES (0xaaa);
ERROR: Data overflow coercing X'aaa' to type bit varying.
문자열 데이터 타입¶
CUBRID는 두 종류의 문자열(character string) 타입을 지원한다.
- 고정길이 문자열 : CHAR (n)
- 가변길이 문자열 : VARCHAR (n)
- 고정길이 국가 문자열 : NCHAR(n)
- 가변길이 국가 문자열 : NCHAR VARYING(n)
다음은 문자열 타입을 사용할 때 적용되는 규칙이다.
문자열은 작은 따옴표로 감싸서 표현한다. SQL 구문 관련 파라미터인 ansi_quotes 의 값에 따라 문자열을 감싸는 부호로 큰 따옴표도 사용할 수 있다. ansi_quotes 값을 no로 설정하면 큰 따옴표로 감싼 문자열을 식별자로 처리하지 않고 문자열로 처리한다. 기본값은 yes 이다. 자세한 설명은 구문/타입 관련 파라미터 를 참고한다.
ANSI 표준에 따라 두 개의 문자열 사이에 공간으로 취급할 수 있는 문자(예: 공백, 탭, 줄바꿈 등)가 있다면, 두 개의 문자열은 연속된 하나의 문자열로 취급된다. 예를 들면, 다음과 같이 두 개의 문자열 사이에 줄바꿈이 있는 경우가 있다.
'abc' 'def'
위 문자열은 아래에 있는 하나의 문자열과 동일하다.
'abcdef'
작은 따옴표 자체를 문자열에 포함시키려면, 두 개의 작은 따옴표를 연속으로 입력하면 된다. 예를 들어, 아래의 왼쪽 문자열은 실제로 오른쪽과 같이 저장된다.
''abcde''fghij' 'abcde'fghij
모든 문자열에 대한 토큰의 최대 크기는 16KB이다.
국가 문자열은 다국어 환경에서 영어 외의 문자열을 저장할 때 사용할 수 있다. 단, 아래 예제와 같이 문자열을 감싸는 시작 따옴표 앞에 반드시 대문자 N을 붙여야 한다.
N'Härder'
길이(Length)
CHAR나 VARVAHR 타입에서는 문자열의 크기(바이트)를 지정하며, NCHAR나 NCHAR VARYING 타입에서는 문자의 개수를 지정한다.
입력된 문자열이 지정된 길이를 초과하는 경우, 지정된 길이에 맞도록 데이터를 자르므로(truncate) 주의한다.
또한, 고정 길이 문자열 타입인 CHAR 에서는 선언한 길이에 고정되므로, 문자를 저장할 때 오른쪽에 공백 문자(trailing space)를 채운다. 한편, 가변 길이 문자열 타입인 VARCHAR 에서는 공백 문자를 채우지 않고 실제 입력된 문자열만큼 저장한다.
CHAR 또는 VARCHAR 타입에서 지정할 수 있는 최대 길이는 1,073,741,823이며, NCHAR 또는 NCHAR VARYING 타입에서 지정할 수 있는 최대 길이는 536,870,911이다. 또한, CSQL 문장으로 한 번에 입력 또는 출력할 수 있는 최대 크기는 8192KB이다.
또한, CSQL 문장으로 한 번에 입력 또는 출력할 수 있는 최대 크기는 8192KB이다.
문자셋(Character Set, charset)
문자셋(문자 집합)은 특정 문자(symbol)를 컴퓨터에 저장할 때, 어떠한 코드로 인코딩할 것인지에 대한 규칙이 정의된 집합을 의미한다. CUBRID가 사용할 문자셋은 CUBRID_LANG 환경 변수로 설정할 수 있다. 멀티 바이트 문자셋에서 비교 연산 및 LIKE 연산을 수행하려면 cubrid.conf의 시스템 파라미터 single_byte_compare의 값을 반드시 yes로 설정해야 한다. 멀티 바이트 문자의 순서는 바이트 순서대로 수행되며, 사전 순서(dictionary order)를 보장하지는 않는다.
문자셋의 정렬(Collating Character Set)
콜레이션(collation)은 어느 문자셋이 설정된 상태에서 데이터베이스에 저장된 값들을 검색하거나 정렬하는 작업을 위해 문자들을 서로 비교할 때 사용하는 규칙들의 집합이다. 따라서 이러한 규칙은 CHAR 또는 VARCHAR와 같은 문자열 데이터 타입에만 적용된다. 단, NCAHR, NCHAR VARYING과 같은 국가 문자열 데이터 타입에서는 해당 문자셋의 인코딩 알고리즘에 따라 정렬 규칙이 결정된다.
문자열 변환(Character String Coercion)
고정길이와 가변길이 문자열 사이에는 두 문자의 길이가 비교 가능할 수 있도록 자동 변환된다. 자동 변환은 동일한 문자셋에 속하는 문자열에만 적용된다.
예를 들어, 데이터 타입이 CHAR (5)인 칼럼을 추출하여 데이터 타입이 CHAR (10)인 칼럼에 삽입하는 경우 자동으로 데이터 타입이 CHAR (10)으로 변환되어 삽입된다. 문자열을 명시적으로 변환할 수도 있는데, 이 때에는 CAST 연산자를 사용한다(
CAST()
참조).
CHAR(n)¶
고정길이 문자열은 CHAR (n)로 표현하며, 여기서 n 은 ASCII 문자열의 바이트 수를 나타내는 것으로, 영문의 경우 한 문자는 1바이트를 차지한다. 한글의 경우 데이터 입력 환경의 문자셋(character set)에 따라 한 문자가 차지하는 바이트 수가 다르므로 주의하여 지정한다(예: EUC-KR: 2바이트, UTF-8: 3바이트). n이 생략되면 길이는 기본값인 1로 지정된다.
문자열의 길이가 n 을 초과하면 초과 부분을 절삭한다. n 보다 작은 문자열이 저장되면 나머지 부분은 공백 문자로 채워진다.
CHAR (n)와 CHARACTER (n)는 같은 의미로 사용된다.
- CHAR는 항상 ISO 8859-1 Latin 문자셋을 사용한다.
- n 은 1부터 1,073,741,823(1G) 사이의 정수이다.
- 공백 값은 빈 따옴표('')로 처리하며, 이 경우 LENGTH 함수의 리턴 값은 0이 아니라 CHAR (n)에서 정의한 고정길이이다. 즉, CHAR (10)인 칼럼에 공백 값을 넣더라도 리턴 값은 10이며, n 이 생략되면 기본값이 1 이므로 CHAR (1)로 간주된다.
- 채우는(padding) 문자로 사용되는 공백은 특수 문자를 비롯한 어느 문자보다도 작은 것으로 간주된다.
CHAR(12)에 'pacesetter'를 저장하면 'pacesetter '가 된다(10자리 문자열과 공백 문자 2개로 구성됨).
CHAR(10)에 'pacesetter '를 저장하면 'pacesetter'가 된다(10을 넘어서는 부분이 공백 문자이므로 이를 절삭하고 10자리 문자열로 구성됨).
CHAR(4)에 'pacesetter'를 저장하면 'pace'가 된다(문자열의 크기가 4보다 크므로 절삭함).
CHAR에 'p '를 저장하면 'p'가 된다(n이 생략되면 길이는 기본값인 1로 지정됨).
- 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.
VARCHAR(n) 또는 CHAR VARYING(n)¶
가변길이 문자열은 VARCHAR (n)로 표현하며, 여기서 n은 ASCII 문자열의 바이트 수를 나타내는 것으로, 영문의 경우 한 문자는 1바이트를 차지한다. 한글의 경우 데이터 입력 환경의 문자셋(character set)에 따라 한 문자가 차지하는 바이트 수가 다르므로 주의하여 지정한다(예: EUC-KR: 2바이트, UTF-8: 3바이트). 만약, n이 생략되면 길이는 최대 길이인 1,073,741,823로 지정된다.
문자열의 길이가 n 을 초과하면 초과 부분을 절삭한다. n 보다 작은 문자열이 저장되면 CHAR (n)는 나머지 부분을 공백 문자로 채우지만 VARCHAR (n)에는 해당 문자열 길이만큼만 저장한다.
VARCHAR (n)와 CHARACTER VARYING (n), CHAR VARYING (n)은 같은 의미로 사용된다.
- STRING 은 VARCHAR (최대 길이)와 같다.
- n 은 1부터 1,073,741,823(1G) 사이의 정수이다.
- 공백 값은 빈 따옴표('')로 처리하며, 이 경우 LENGTH 함수의 리턴 값은 0이다.
VARCHAR(4)에 'pacesetter'를 저장하면 'pace'가 된다(문자열의 크기가 4보다 크므로 절삭함).
VARCHAR(12)에 'pacesetter'를 저장하면 'pacesetter'가 된다(10자리 문자열로 구성됨).
VARCHAR(12)에 'pacesetter '를 저장하면 'pacesetter '가 된다(10자리 문자열과 공백 문자 2개로 구성됨).
VARCHAR(10)에 'pacesetter '를 저장하면 'pacesetter'가 된다(10을 넘어서는 부분이 공백 문자이므로 이를 절삭하고 10자리 문자열로 구성됨).
VARCHAR에 'p '를 저장하면 'p'가 된다(n이 생략되면 최대 길이는 기본값인 1,073,741,823로 지정되고, 저장 시 나머지 부분은 공백 문자로 채워지지 않음).
- 이 타입의 칼럼에 DEFAULT 속성이 지정될 수 있다.
STRING¶
STRING 은 가변길이 문자열 데이터 타입이다. STRING 은 VARCHAR 를 최대 길이로 지정한 것과 같다. 즉 STRING 은 VARCHAR (1,073,741,823)과 동일하다.
NCHAR(n)¶
NCHAR (n)는 영어권 외 국가에서 문자열을 저장할 때 사용할 수 있는 타입으로서, 앞에서 설명한 CUBRID 지원 문자셋의 경우에만 사용할 수 있다. n은 문자의 개수를 나타내며, n이 생략되면 길이는 기본값 1로 지정된다.
문자열의 크기가 n을 초과하면 초과 부분을 절삭한다. n보다 작은 문자열이 저장되면 나머지 부분이 공백 문자로 채워진다.
국가 문자열 타입에 한글을 저장하기 위해서는 테이블 생성 이전에, 운영 체제의 로캘(locale)을 korean으로 설정하거나 CUBRID_LANG 환경 변수의 값을 ko_KR.euckr로 설정해야 한다.
NCHAR (n)와 NATIONAL CHAR (n), 그리고 NATIONAL CHARACTER (n)는 같은 의미로 사용된다.
- n은 1부터 536,870,911 사이의 정수이다.
- 하나의 데이터베이스에서 사용할 수 있는 국가 문자셋은 하나로 지정되어 있다. 예를 들어, 같은 데이터베이스에서 8비트 ISO 8889-1 Latin 코드 세트를 사용하면서 동시에 EUC 인코딩 코드 세트를 사용할 수는 없다.
- 국가 문자열로 선언된 칼럼에 고정이든 가변이든 일반 문자열을 지정하면 오류가 발생한다.
- 서로 다른 문자셋을 혼용하여 사용할 경우에도 오류가 발생한다.
NCHAR VARYING(n)¶
NCHAR VARYING (n)은 가변길이의 국가 문자열 타입이며, 이에 대한 설명은 NCHAR (n)의 설명 및 참고 사항을 참고한다. NCHAR (n)와의 차이점은 문자의 개수가 n보다 작아도 오른쪽 부분에 공백 문자(trailing space)를 채우지 않는다는 것이다.
NCHAR VARYING (n)와 NATIONAL CHAR VARYING (n), 그리고 NATIONAL CHARACTER VARYING (n)는 같은 의미로 사용된다.
EUC-KR 환경에서 NCHAR VARYING(5)에 '큐브리드'를 저장하면 정상적으로 저장된다.
EUC-KR 환경에서 NCHAR VARYING(5)에 '큐브리드'를 저장한 후 CHAR_LENGTH() 함수를 사용하면 4가 출력된다.
UTF-8 환경에서 NCHAR VARYING(5)에 '큐브리드'를 저장하면 오류가 발생한다(UTF-8 문자셋을 지원하지 않음).
특수 문자 이스케이프¶
CUBRID는 특수 문자를 이스케이프(escape)하는 방법을 두 가지 지원한다. 하나는 따옴표를 이용한 방법이고, 다른 하나는 백슬래시(\)를 이용한 방법이다.
따옴표 이스케이프
cubrid.conf 의 시스템 파라미터 ansi_quotes가 no로 설정되어 있으면 문자열을 감쌀 때 큰따옴표(")와 작은따옴표(') 둘 다 사용할 수 있다. ansi_quotes 파라미터의 기본값은 yes 로, 문자열을 감쌀 때 작은따옴표만 사용할 수 있다.
- 작은따옴표로 감싼 문자열에 포함된 작은따옴표는 두 개의 작은따옴표('')를 쓴다.
- 큰따옴표로 감싼 문자열에 포함된 큰따옴표는 두 개의 큰따옴표("")를 쓴다. (ansi_quotes 값이 no인 경우)
- 큰따옴표로 감싼 문자열에 포함된 작은따옴표는 이스케이프하지 않아도 된다. (ansi_quotes 값이 no인 경우)
- 작은따옴표로 감싼 문자열에 포함된 큰따옴표는 이스케이프하지 않아도 된다.
백슬래시 이스케이프
백슬래시(\)를 이용한 이스케이프는 cubrid.conf의 시스템 파라미터 no_backslash_escapes를 no로 설정했을 때에만 사용할 수 있다. no_backslash_escapes 파라미터의 기본값은 yes 이다. no_backslash_escapes의 값이 no인 경우, 다음과 같은 특수 문자를 의미한다.
- \' : 작은따옴표(')
- \" : 큰따옴표(")
- \n : 뉴라인(newline, linefeed) 문자
- \r : 캐리지 리턴(carriage return) 문자
- \t : 탭(tab) 문자
- \\ : 백슬래시(backslash)
- \% : 퍼센트 기호(%). 자세한 내용은 아래 설명을 참고한다.
- \_ : 언더바(_). 자세한 내용은 아래 설명을 참고한다.
다른 모든 이스케이프에 대해서는 백슬래시가 무시된다. 예를 들어 "x"는 그냥 "x"라고 입력한 것과 같다.
\% 와 \_ 는 LIKE 와 같은 패턴 매칭 구문에서 퍼센트 기호와 언더바를 찾을 때 쓰이며, 백슬래시가 없으면 와일드카드 문자(wildcard character)로 쓰인다. 패턴 매칭 구문 밖에서는 와일드카드 문자가 아닌 일반 문자열 "\%"와 "\_"로 그대로 쓰인다. 자세한 내용은 LIKE 을 참고한다.
다음은 cubrid.conf의 시스템 파라미터 ansi_quotes가 yes(기본값)이고 no_backslash_escapes가 no일 때 백슬래시에 대해 이스케이프를 수행한 결과이다.
-- ansi_quotes=yes, no_backslash_escapes=no
SELECT STRCMP('single quotes test('')', 'single quotes test(\')');
위의 구문을 실행하면, 백슬래시가 이스케이프 문자로 인식되므로 두 문자열은 같은 것으로 인식된다.
strcmp('single quotes test('')', 'single quotes test('')')
=============================================================
0
SELECT STRCMP('\a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z', 'a\bcdefghijklm\nopq\rs\tuvwxyz');
위의 구문을 실행하면, 백슬래시가 이스케이프 문자로 인식되므로 두 문자열은 같은 것으로 인식된다.
strcmp('abcdefghijklm
s uvwxyz', 'abcdefghijklm
s uvwxyz')
=====================================================================
0
SELECT LENGTH('\\');
위의 구문을 실행하면, 백슬래시가 이스케이프 문자로 인식되므로 문자열의 길이는 1이 된다.
char_length('\')
===================
1
다음은 cubrid.conf의 시스템 파라미터 ansi_quotes가 yes(기본값)이고 no_backslash_escapes가 yes(기본값)일 때 수행한 결과이다. 백슬래시는 일반 문자로 인식된다.
-- ansi_quotes=yes, no_backslash_escapes=yes
SELECT STRCMP('single quotes test('')', 'single quotes test(\')');
위의 구문을 실행하면, 아직 따옴표가 열린 것으로 간주하여 아래와 같은 에러가 발생한다. CSQL 인터프리터의 SQL 입력 화면에서 위의 구문을 입력하면 다음 따옴표가 입력되기를 대기한다.
ERROR: syntax error, unexpected UNTERMINATED_STRING, expecting SELECT or VALUE or VALUES or '('
SELECT STRCMP('\a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z', 'a\bcdefghijklm\nopq\rs\tuvwxyz');
위의 구문을 실행하면, 백슬래시가 일반 문자로 인식되므로 두 문자열의 비교 결과는 서로 다른 것으로 인식된다.
strcmp('\a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z', 'a\bcdefghijklm\nopq\rs\tuvwxyz')
===================================================================================================
-1
SELECT LENGTH('\\');
위의 구문을 실행하면, 백슬래시가 일반 문자로 인식되므로 문자열의 길이는 2가 된다.
char_length('\\')
====================
2
다음은 cubrid.conf의 시스템 파라미터 ansi_quotes가 yes이고 no_backslash_escapes가 no일 때 LIKE 절에 대해 이스케이프를 수행한 결과이다.
-- ansi_quotes=yes, no_backslash_escapes=no
CREATE TABLE t1 (a VARCHAR(200));
INSERT INTO t1 VALUES ('aaabbb'), ('aaa%');
SELECT a FROM t1 WHERE a LIKE 'aaa\%' ESCAPE '\\';
a
======================
'aaa%'
'%'가 패턴 매칭 문자가 아닌 일반 문자로 인식되기 때문에, 질의를 수행하면 1개의 행만 리턴한다.
LIKE 절의 문자열에서는 백슬래시가 항상 일반 문자로 간주되기 때문에, '%'를 패턴 매칭 문자가 아닌 일반 문자로 인식시키려면 ESCAPE 절을 지정하여 백슬래시가 이스케이프 문자임을 명시해야 한다. ESCAPE 절에서는 백슬래시가 이스케이프 문자로 간주되기 때문에, 두 개의 백슬래시 문자를 사용했다.
위의 SELECT 질의에서 이스케이프 문자를 백슬래시가 아닌 다른 문자로 쓰려면 아래와 같이 사용할 수 있다.
SELECT a FROM t1 WHERE a LIKE 'aaa#%' ESCAPE '#';
BLOB/CLOB 데이터 타입¶
External LOB(Large Object) 타입은 텍스트 또는 이미지 등 크기가 큰 객체를 처리하기 위한 데이터 타입이다. LOB 타입 데이터가 생성 및 삽입되면 이는 외부 저장소에 파일로 저장되고 CUBRID 데이터베이스에는 해당 파일의 위치 정보(LOB locator)가 저장된다. 데이터베이스에서 해당 데이터(LOB locator)가 삭제되면, 외부 저장소에 저장된 해당 파일이 함께 삭제된다. CUBRID는 두 가지 LOB 타입을 지원한다.
- Binary Large Object(BLOB)
- Character Large Object(CLOB)
Note
관련 용어
- LOB (Large Object): 이진 바이너리 또는 텍스트 등 크기가 큰 객체이다.
- FBO (File Based Object): DB 데이터를 DB 외부의 파일로 저장하는 객체이다.
- External LOB: LOB 데이터를 DB 외부에 파일로 저장하는 객체로서 FBO라고도 하며, CUBRID는 이를 지원한다. Internal LOB은 LOB 데이터를 DB 내부에 저장하는 객체이다.
- External Storage: LOB을 저장하는 외부 저장소이다(예: POSIX 파일 시스템).
- LOB Locator: 외부 저장소에 저장된 파일의 경로명이다.
- LOB Data: LOB Locator에 명시된 위치에 있는 파일의 내용이다.
LOB 데이터는 외부 저장소에 다음과 같은 파일명으로 저장된다.
{table_name}_{unique_name}
- table_name : prefix로 삽입되어 하나의 외부 저장소에 여러 테이블의 LOB 데이터를 저장할 수 있다.
- unique_name : 데이터베이스 서버가 임의로 생성하는 이름이다.
LOB 데이터의 저장소는 데이터베이스 서버 상의 로컬 파일 시스템이다. LOB 데이터는 cubrid createdb 유틸리티의 -lob-base-path 옵션 값으로 지정된 경로에 저장되며, 옵션이 생략될 경우 데이터베이스 볼륨이 생성되는 [db-vol path]/lob 경로에 저장된다. 보다 자세한 내용은 데이터베이스 생성 및 저장소 생성 및 관리 를 참고한다.
CUBRID가 제공하는 API나 도구를 사용하지 않고 사용자가 임의로 LOB 파일 내용을 수정하면, 해당 내용의 일치성이 보장되지 않으므로 주의한다.
데이터베이스 위치 정보 파일(databases.txt)에 LOB 데이터 파일 경로가 등록되어 있음에도 불구하고 해당 경로가 삭제된 경우, 데이터베이스 서버(cub_server) 및 독립 모드(standalone)로 동작하는 유틸리티가 정상적으로 실행되지 않으므로 주의한다.
BLOB¶
바이너리 데이터를 DB 외부에 저장하기 위한 타입으로, BLOB 데이터의 최대 길이는 외부 저장소에서 생성 가능한 파일 크기이다. BLOB 타입은 SQL 문에서 비트열 타입으로 입출력 값을 표현한다. 즉, BIT (n), BIT VARYING (n) 타입과 호환되며, 명시적 타입 변환만 허용된다. 데이터 길이가 서로 다른 경우에는 최대 길이가 작은 타입에 맞추어 절삭(truncate)된다. BLOB 타입 값을 바이너리 값으로 변환하는 경우, 변환된 데이터는 최대 1GB를 넘을 수 없다. 반대로 바이너리를 BLOB 타입으로 변환하는 경우, 변환된 데이터는 BLOB 저장소에서 제공하는 최대 파일 크기를 넘을 수 없다.
CLOB¶
문자열 데이터를 DB 외부에 저장하기 위한 타입으로, CLOB 데이터의 최대 길이는 외부 저장소에서 생성 가능한 파일 크기이다. CLOB 타입은 SQL 문에서 문자열 타입으로 입출력 값을 표현한다. 즉, CHAR (n), VARCHAR (n) 타입과 호환된다. 단, 명시적 타입 변환만 허용되며, 데이터 길이가 서로 다른 경우에는 최대 길이가 작은 타입에 맞추어 절삭(truncate)된다. CLOB 타입 값을 문자열 값으로 변환하는 경우, 변환된 데이터는 최대 1GB를 넘을 수 없다. 반대로 문자열을 CLOB 타입으로 변환하는 경우, 변환된 데이터는 CLOB 저장소에서 제공하는 최대 파일 크기를 넘을 수 없다.
정의 및 변경¶
CREATE TABLE 문 또는 ALTER TABLE 문을 사용하여 BLOB / CLOB 타입 칼럼을 생성/추가/삭제할 수 있다.
- LOB 타입 칼럼에 대해서는 인덱스를 생성할 수 없다.
- LOB 타입 칼럼에 대해서는 PRIMARY KEY, FOREIGN KEY, UNIQUE, NOT NULL 제약 조건을 정의할 수 없다. 또한, SHARED 속성을 정의할 수 없으며, DEFAULT 속성은 NULL 값에 대해서만 정의할 수 있다.
- LOB 타입 칼럼/데이터는 컬렉션 타입의 원소가 될 수 없다.
- LOB 타입 칼럼이 있는 레코드를 삭제하는 경우, LOB 칼럼 값(Locator) 및 외부 저장소 내 파일을 모두 삭제한다. 또한, 기본 키 테이블에서 LOB 타입 칼럼이 있는 레코드가 삭제됨에 따라 이를 참조하는 외래 키 테이블의 레코드가 함께 삭제되는 경우, LOB 칼럼 값(Locator) 및 외부 저장소 내 LOB 파일을 모두 삭제한다. 단, ALTER TABLE ... DROP 문을 사용하여 LOB 칼럼을 삭제하거나 DROP TABLE 문을 사용하여 해당 테이블을 삭제하는 경우, LOB 칼럼 값(Lob locator)만 삭제하고 LOB 칼럼이 참조하는 외부 저장소 내 LOB 파일은 삭제하지 않는다.
-- creating a table and CLOB column
CREATE TABLE doc_t (doc_id VARCHAR(64) PRIMARY KEY, content CLOB);
-- an error occurs when UNIQUE constraint is defined on CLOB column
ALTER TABLE doc_t ADD CONSTRAINT content_unique UNIQUE(content);
-- an error occurs when creating an index on CLOB column
CREATE INDEX i_doc_t_content ON doc_t (content);
-- creating a table and BLOB column
CREATE TABLE image_t (image_id VARCHAR(36) PRIMARY KEY, doc_id VARCHAR(64) NOT NULL, image BLOB);
-- an error occurs when adding a BOLB column with NOT NULL constraint
ALTER TABLE image_t ADD COLUMN thumbnail BLOB NOT NULL;
-- an error occurs when adding a BLOB column with DEFAULT attribute
ALTER TABLE image_t ADD COLUMN thumbnail2 BLOB DEFAULT BIT_TO_BLOB(X'010101');
저장 및 변경¶
BLOB / CLOB 타입 칼럼에는 각각 BLOB / CLOB 타입 값이 저장되며, 바이너리 또는 문자열 데이터를 입력하는 경우에는 각각 BIT_TO_BLOB()
, CHAR_TO_CLOB()
함수를 사용하여 명시적으로 타입을 변환을 수행하여야 한다.
INSERT 문을 사용하여 LOB 칼럼에 값을 입력하면, 내부적으로는 외부 저장소에 파일을 생성하여 해당 데이터를 저장하고, 실제 칼럼 값으로 해당 파일의 경로(Locator) 정보를 저장한다.
DELETE 문을 사용하여 LOB 칼럼이 존재하는 레코드를 삭제하면, 해당 LOB 칼럼 값이 참조하는 파일을 함께 삭제한다.
UPDATE 문을 사용하여 LOB 칼럼 값을 변경하는 경우, 새로운 값이 NULL 인지에 따라 다음과 같이 동작하면서 칼럼 값을 변경한다.
- LOB 타입 칼럼 값을 NULL 이 아닌 값으로 변경하는 경우: LOB 칼럼에 이미 외부 파일을 참조하는 locator 가 저장되어 있다면, 해당 파일을 삭제한다. 그리고 새로운 파일을 생성하여 NULL이 아닌 값을 저장한 후, LOB 칼럼 값에 새로운 파일에 대한 locator를 저장한다.
- LOB 타입 칼럼 값을 NULL 로 변경하는 경우: LOB 칼럼에 이미 외부 파일을 참조하는 locator 가 저장되어 있다면, 해당 파일을 삭제한다. 그리고 LOB 칼럼 값에 NULL을 바로 저장한다.
-- inserting data after explicit type conversion into CLOB type column
INSERT INTO doc_t (doc_id, content) VALUES ('doc-1', CHAR_TO_CLOB('This is a Dog'));
INSERT INTO doc_t (doc_id, content) VALUES ('doc-2', CHAR_TO_CLOB('This is a Cat'));
-- inserting data after explicit type conversion into BLOB type column
INSERT INTO image_t VALUES ('image-0', 'doc-0', BIT_TO_BLOB(X'000001'));
INSERT INTO image_t VALUES ('image-1', 'doc-1', BIT_TO_BLOB(X'000010'));
INSERT INTO image_t VALUES ('image-2', 'doc-2', BIT_TO_BLOB(X'000100'));
-- inserting data from a sub-query result
INSERT INTO image_t SELECT 'image-1010', 'doc-1010', image FROM image_t WHERE image_id = 'image-0';
-- updating CLOB column value to NULL
UPDATE doc_t SET content = NULL WHERE doc_id = 'doc-1';
-- updating CLOB column value
UPDATE doc_t SET content = CHAR_TO_CLOB('This is a Dog') WHERE doc_id = 'doc-1';
-- updating BLOB column value
UPDATE image_t SET image = (SELECT image FROM image_t WHERE image_id = 'image-0') WHERE image_id = 'image-1';
-- deleting BLOB column value and its referencing files
DELETE FROM image_t WHERE image_id = 'image-1010';
조회¶
LOB 타입 칼럼을 조회하면 칼럼이 참조하는 파일에 저장된 데이터를 출력한다. CAST()
연산자, CLOB_TO_CHAR()
함수, BLOB_TO_BIT()
함수를 사용하여 명시적 타입 변환을 수행할 수 있다.
- CSQL에서 질의를 실행할 경우, 파일에 저장된 데이터가 아닌 칼럼 값(Locator)을 출력한다. BLOB / CLOB 칼럼이 참조하는 데이터를 출력하기 위해서는
CLOB_TO_CHAR()
함수를 사용하여 문자열로 변환해야 한다. - 문자열 처리 함수를 사용하기 위해서는
CLOB_TO_CHAR()
함수를 사용하여 문자열로 변환해야 한다. - GROUP BY 절, ORDER BY 절에 LOB 칼럼을 명시할 수 없다.
- 비교 연산자, 관계 연산자, IN, NOT IN 연산자를 사용하여 LOB 칼럼을 비교할 수 없다. 단, IS NULL 조건식을 사용하여 LOB 칼럼 값(locator)이 NULL 인지 비교할 수 있다. 즉, 칼럼 값이 NULL이면 TRUE를 반환하는데, 칼럼 값이 NULL인 경우는 LOB 데이터를 저장하는 파일이 존재하지 않는다는 의미이다.
- LOB 칼럼을 생성하고 데이터를 입력한 이후 LOB 데이터 파일을 삭제하면, LOB 칼럼 값(locator)이 유효하지 않은 파일을 참조하는 상태가 된다. 이처럼 LOB locator와 LOB 데이터 파일이 매칭되지 않는 칼럼에 대해
CLOB_TO_CHAR()
,BLOB_TO_BIT()
,CLOB_LENGTH()
,BLOB_LENGTH()
함수를 사용하면 NULL을 출력한다.
-- displaying locator value when selecting CLOB and BLOB column in CSQL interpreter
SELECT doc_t.doc_id, content, image FROM doc_t, image_t WHERE doc_t.doc_id = image_t.doc_id;
doc_id content image
==================================================================
'doc-1' file:/home1/data1/ces_658/doc_t.00001282208855807171_7329 file:/home1/data1/ces_318/image_t.00001282208855809474_7474
'doc-2' file:/home1/data1/ces_180/doc_t.00001282208854194135_5598 file:/home1/data1/ces_519/image_t.00001282208854205773_1215
2 rows selected.
-- using string functions after coercing its type by CLOB_TO_CHAR( )
SELECT CLOB_TO_CHAR(content), SUBSTRING(CLOB_TO_CHAR(content), 10) FROM doc_t;
clob_to_char(content) substring( clob_to_char(content) from 10)
============================================
'This is a Dog' ' Dog'
'This is a Cat' ' Cat'
2 rows selected.
SELECT CLOB_TO_CHAR(content) FROM doc_t WHERE CLOB_TO_CHAR(content) LIKE '%Dog%';
clob_to_char(content)
======================
'This is a Dog'
SELECT CLOB_TO_CHAR(content) FROM doc_t ORDER BY CLOB_TO_CHAR(content);
clob_to_char(content)
======================
'This is a Cat'
'This is a Dog'
SELECT * FROM doc_t WHERE content LIKE 'This%';
doc_id content
============================================
'doc-1' file:/home1/data1/ces_004/doc_t.00001366272829040346_0773
'doc-2' file:/home1/data1/ces_256/doc_t.00001366272815153996_1229
-- an error occurs when LOB column specified in ORDER BY/GROUP BY clauses
SELECT * FROM doc_t ORDER BY content;
ERROR: doc_t.content can not be an ORDER BY column
연산자와 함수¶
CAST()
연산자를 사용하여 BLOB / CLOB 타입과 바이너리 타입/문자열 타입 간 명시적 타입 변환을 수행할 수 있다. 자세한 내용은 CAST()
연산자를 참고한다.
CAST (<bit_type_column_or_value> AS { BLOB | CLOB })
CAST (<char_type_column_or_value> AS { BLOB | CLOB })
다음은 BLOB / CLOB 타입 처리 및 변환을 위해 제공하는 함수이다. 자세한 설명은 LOB 함수 절을 참고한다.
CLOB_TO_CHAR()
BLOB_TO_BIT()
CHAR_TO_CLOB()
BIT_TO_BLOB()
CHAR_TO_BLOB()
CLOB_FROM_FILE()
BLOB_FROM_FILE()
CLOB_LENGTH()
BLOB_LENGTH()
Note
" <blob_or_clob_column> IS NULL ": IS NULL 조건식을 사용하여 LOB 칼럼 값(Locator)이 NULL 인지 비교하고, NULL 이면 TRUE 를 반환한다.
저장소 생성 및 관리¶
LOB 데이터 파일은 기본적으로 데이터베이스 볼륨이 생성되는 <db-volume-path>/lob 디렉터리에 저장된다. 데이터베이스 생성 시 createdb -B
옵션을 통해서 LOB 데이터 파일을 저장할 디렉터리를 지정할 수 있다. 지정된 디렉터리가 존재하지 않으면 디렉터리 생성을 시도하며, 생성 실패 시에는 에러를 출력한다. 자세한 내용은 createdb -B
옵션을 참고한다.
# 현재 작업 디렉터리에 image_db 볼륨이 생성되고 LOB 데이터 파일이 저장된다.
% cubrid createdb image_db
# 로컬 파일 시스템 내 "/home1/data1" 경로에 LOB 데이터 파일이 저장된다.
% cubrid createdb --lob-base-path="file:/home1/data1" image_db
spacedb 유틸리티를 실행하여 LOB 파일이 저장되는 디렉터리를 확인할 수 있다.
% cubrid spacedb image_db
Space description for database 'image_db' with pagesize 16.0K. (log pagesize: 16.0K)
Volid Purpose total_size free_size Vol Name
0 GENERIC 512.0M 510.1M /home1/data1/image_db
Space description for temporary volumes for database 'image_db' with pagesize 16.0K.
Volid Purpose total_size free_size Vol Name
LOB space description file:/home1/data1
파일 저장소를 추가로 생성하려면 디스크 공간을 확보한 후 databases.txt 의 lob-base-path 를 증설한 디스크 위치로 변경한다. databases.txt 의 변경 내용을 반영하기 위하여 DB 서버를 재구동한다. 단, databases.txt 의 lob-base-path 를 변경하더라도 이전 저장소에 저장된 LOB 데이터는 접근 가능하다.
# You can change to a new directory from the lob-base-path of databases.txt file.
% cat $CUBRID_DATABASES/databases.txt
#db-name vol-path db-host log-path lob-base-path
image_db /home1/data1 localhost /home1/data1 file:/home1/data2
LOB 타입 칼럼의 데이터 파일에 대한 백업 및 복구는 지원하지 않으며, LOB 타입 칼럼의 메타 데이터 값(Locator)에 대해서만 백업 및 복구를 지원한다.
copydb 유틸리티를 사용하여 데이터베이스를 복사하는 경우, 관련 옵션이 지정되지 않으면 LOB 파일 디렉터리 경로가 복사되지 않으므로 추가로 databases.txt 파일을 설정해야 한다. 자세한 내용은 copydb 유틸리티의 copydb -B
및 copydb --copy-lob-path
옵션을 참고한다.
트랜잭션 지원 및 복구¶
LOB 데이터 변경에 대한 커밋/롤백을 지원한다. 즉, 트랜잭션 내에서 LOB Locator와 실제 LOB 데이터의 매핑(mapping)에 대한 유효성을 보장하고, 데이터베이스 장애 시 회복(recovery)을 지원한다. 트랜잭션 수행 도중 데이터베이스가 종료되어 해당 트랜잭션이 롤백 처리됨에 따라 LOB Locator와 LOB 데이터 간 매핑이 일치하지 않으면 에러를 출력한다. 아래의 예를 참고한다.
-- csql> ;AUTOCOMMIT OFF
CREATE TABLE doc_t (doc_id VARCHAR(64) PRIMARY KEY, content CLOB);
INSERT INTO doc_t VALUES ('doc-10', CHAR_TO_CLOB('This is content'));
COMMIT;
UPDATE doc_t SET content = CHAR_TO_CLOB('This is content 2') WHERE doc_id = 'doc-10';
ROLLBACK;
SELECT doc_id, CLOB_TO_CHAR(content) FROM doc_t WHERE doc_id = 'doc-10';
doc_id content
=========================================================
'doc-10' 'This is content'
-- csql> ;AUTOCOMMIT OFF
INSERT INTO doc_t VALUES ('doc-11', CHAR_TO_CLOB ('This is content'));
COMMIT;
UPDATE doc_t SET content = CHAR_TO_CLOB('This is content 3') WHERE doc_id = 'doc-11';
-- system crash occurred and then restart server
SELECT doc_id, CLOB_TO_CHAR(content) FROM doc_t WHERE doc_id = 'doc-11';
-- Error : LOB Locator references to the previous LOB data because only LOB Locator is rollbacked.
Note
- JDBC와 같은 드라이버를 통해 애플리케이션에서 LOB 데이터를 조회하는 경우, JDBC는 데이터베이스 서버로부터 ResultSet을 가져온 후 Resultset에 대해 커서(cursor) 위치를 변경하면서 레코드를 인출할 수 있다. 즉, ResultSet을 가져온 시점에는 LOB 칼럼의 메타 데이터인 Locator만 저장되어 있고, 레코드를 인출하는 시점에 Locator가 참조하는 파일로부터 LOB 데이터가 실제로 인출된다. 따라서, 두 시점 사이에 LOB 데이터가 업데이트되는 경우, LOB Locator와 실제 LOB 데이터의 매핑(mapping)이 유효하지 않아 에러가 발생할 수 있다.
- LOB 타입 칼럼의 메타 데이터(Locator)에 대해서만 백업/복구를 지원한다. 따라서, 장애가 발생해서 특정 시점으로 복구할 때 LOB Locator와 LOB 데이터의 매핑이 유효하지 않아 에러가 발생할 수 있다.
- LOB 데이터를 다른 장비에 INSERT 하려면 반드시 LOB 칼럼 메타 데이터(Locator)가 참조하는 LOB 데이터를 읽어서 INSERT 해야 한다.
- CUBRID HA에서 LOB 칼럼 메타 데이터(Locator)는 복제되고, LOB 데이터는 복제되지 않는다. 따라서 LOB 타입 저장소가 로컬에 위치할 경우, 슬레이브 노드 또는 failover 이후 마스터 노드에서 해당 칼럼에 대한 작업을 허용하지 않는다.
Warning
CUBRID 2008 R3.0 이하 버전에서는 glo (Generalized Large Object) 클래스를 사용하여 Large Object를 처리했으나, CUBRID 2008 R3.1 버전부터는 glo 클래스를 제거하고 BLOB / CLOB 데이터 타입을 지원한다. 따라서, 이전 버전의 glo 클래스를 사용하는 환경에서는 CUBRID 버전 업그레이드를 수행할 때 DB 스키마 및 애플리케이션을 수정해야 한다.
컬렉션 데이터 타입¶
여러 개의 데이터 값을 하나의 속성에 저장할 수 있도록 하는 컬렉션 데이터 타입은 관계형 데이터베이스의 확장된 기능이다. 컬렉션의 각 원소는 하나의 데이터 타입이어야 하며, 테이블(단, 뷰는 제외) 타입이 될 수도 있다. BLOB, CLOB 타입을 제외한 나머지 타입들은 컬렉션 타입의 원소가 될 수 있다.
타입 | 설명 | 타입 정의 | 입력 데이터 | 저장 데이터 |
---|---|---|---|---|
SET | 중복을 허용하지 않는 합집합 | col_name SET VARCHAR(20) 또는 col_name SET (VARCHAR(20)) | {'c','c','c','b','b','a'} | {'a','b','c'} |
MULTISET | 중복을 허용하는 합집합 | col_name MULTISET VARCHAR(20) 또는 col_name MULTISET (VARCHAR(20)) | {'c','c','c','b','b','a'} | {'a','b','b','c','c','c'} |
LIST 또는 SEQUENCE | 중복을 허용하고, 데이터 입력 순서대로 저장하는 합집합 | col_name LIST VARCHAR(20) 또는 col_name LIST (VARCHAR(20)) | {'c','c','c','b','b','a'} | {'c','c','c','b','b','a'} |
위의 표와 같이, 컬렉션 타입으로 지정되는 값은 중괄호('{', '}') 안에 각 값들을 쉼표(,)로 구분하여 나열할 수 있다.
컬렉션 타입은 지정된 타입이 같다면 CAST 연산자를 이용하여 명시적으로 타입 변환이 가능하다. 아래 표는 명시적 변환이 가능한 컬렉션 타입에 관한 것이다.
FROM \ TO SET MULTISET LIST SET - Yes Yes MULTISET Yes - No LIST Yes Yes -
SET¶
SET 는 각 원소가 서로 다른 값을 갖는 집합이다. SET 의 원소는 하나의 데이터 타입을 가져야 하고, 다른 테이블의 레코드를 가질 수도 있다.
CREATE TABLE set_tbl (col_1 SET (CHAR(1)));
INSERT INTO set_tbl VALUES ({'c','c','c','b','b','a'});
INSERT INTO set_tbl VALUES ({NULL});
INSERT INTO set_tbl VALUES ({''});
SELECT * FROM set_tbl;
col_1
======================
{'a', 'b', 'c'}
{NULL}
{' '}
SELECT CAST (col_1 AS MULTISET), CAST (col_1 AS LIST) FROM set_tbl;
cast(col_1 as multiset) cast(col_1 as sequence)
============================================
{'a', 'b', 'c'} {'a', 'b', 'c'}
{NULL} {NULL}
{' '} {' '}
INSERT INTO set_tbl VALUES ('');
ERROR: Casting '' to type set is not supported.
MULTISET¶
MULTISET 는 중복이 허용되는 집합이다. MULTISET 의 원소는 하나의 데이터 타입을 가져야 하고, 다른 테이블의 레코드를 가질 수도 있다.
CREATE TABLE multiset_tbl (col_1 MULTISET (CHAR(1)));
INSERT INTO multiset_tbl VALUES ({'c','c','c','b','b', 'a'});
SELECT * FROM multiset_tbl;
col_1
======================
{'a', 'b', 'b', 'c', 'c', 'c'}
SELECT CAST(col_1 AS SET), CAST(col_1 AS LIST) FROM multiset_tbl;
cast(col_1 as set) cast(col_1 as sequence)
============================================
{'a', 'b', 'c'} {'c', 'c', 'c', 'b', 'b', 'a'}
LIST 또는 SEQUENCE¶
LIST (SEQUENCE) 는 원소가 입력된 순서가 유지되며, 중복이 허용되는 집합이다. LIST 의 원소는 하나의 데이터 타입을 가져야 하고, 다른 테이블의 레코드를 가질 수도 있다.
CREATE TABLE list_tbl (col_1 LIST (CHAR(1)));
INSERT INTO list_tbl VALUES ({'c','c','c','b','b', 'a'});
SELECT * FROM list_tbl;
col_1
======================
{'c', 'c', 'c', 'b', 'b', 'a'}
SELECT CAST(col_1 AS SET), CAST(col_1 AS MULTISET) FROM list_tbl;
cast(col_1 as set) cast(col_1 as multiset)
============================================
{'a', 'b', 'c'} {'a', 'b', 'b', 'c', 'c', 'c'}
묵시적 타입 변환¶
표현식 내에서 타입을 변환해야 할 때 자동으로 해당 타입으로 변환하는 것을 묵시적 타입 변환(implicit type conversion)이라고 한다.
SET, MULTISET, LIST, SEQUENCE 는 명시적으로 변환되어야 한다.
DATETIME, TIMESTAMP 타입을 DATE 타입이나 TIME 타입으로 변환하면 데이터의 일부가 유실될 수 있다. DATE 타입을 DATETIME 타입이나 TIMESTAMP 타입으로 변환하면, 시간은 '12:00:00 AM'으로 설정된다.
문자열 타입이나 정확한 수치형 타입을 부동소수점 수치형 타입으로 변환하면 값이 정확하지 않을 수 있다. 문자열 타입과 정확한 수치형 타입은 값을 표현하기 위해 십진 정밀도(decimal precision)를 사용하지만 부동소수점 수치형 타입은 이진 정밀도(binary precision)를 사용하기 때문이다.
CUBRID가 수행하는 묵시적 타입 변환은 다음과 같다.
묵시적 타입 변환 표 1
From \ To DATETIME DATE TIME TIMESTAMP DOUBLE FLOAT NUMERIC BIGINT DATETIME - O O O DATE O - O TIME - TIMESTAMP O O O - DOUBLE O O - O O O FLOAT O O O - O O NUMERIC O O O - O BIGINT O O O O O - INT O O O O O O SHORT O O O O O O BIT VARBIT CHAR O O O O O O O O VARCHAR O O O O O O O O
숫자가 TIME 또는 TIMESTAMP로 변환될 때 제약 조건
- NUMERIC을 제외한 모든 숫자 타입은 TIME 타입으로 변환될 수 있는데, 이 때 TIME은 입력 숫자를 86400초(하루)로 나눈 나머지 값을 초로 계산하여 시간을 표현한다.
- NUMERIC을 포함한 모든 숫자 타입은 TIMESTAMP 타입으로 변환될 수 있는데, 이 때 입력 숫자 값은 최대 2147483647을 초과할 수 없다.
묵시적 타입 변환 표 2
From \ To INT SHORT BIT VARBIT CHAR VARCHAR DATETIME O O DATE O O TIME O O TIMESTAMP O O DOUBLE O O O O FLOAT O O O O NUMERIC O O O O BIGINT O O O O INT - O O O SHORT O - O O BIT - O O O VARBIT O - O O CHAR O O O O - O VARCHAR O O O O O -
변환 규칙¶
INSERT와 UPDATE¶
영향을 받는 칼럼의 타입으로 값의 타입이 변환된다.
CREATE TABLE t(i INT);
INSERT INTO t VALUES('123');
SELECT * FROM t;
i
=============
123
함수¶
함수에 입력한 인자 값을 함수에서 지정한 타입으로 변환할 수 있으면 인자의 타입이 변환된다. 아래 함수에서 기대하는 입력 인자는 숫자이므로, 문자열을 숫자로 변환한다.
SELECT MOD('123','2');
mod('123', '2')
==========================
1.000000000000000e+00
함수는 인자로 여러 타입의 값을 입력받을 수 있는데, 함수에서 지정하지 않은 타입의 값이 전달되면 다음의 우선순위에 따라 타입이 변환된다.
- 날짜/시간 타입( DATETIME > TIMESTAMP > DATE > TIME )
- 근사치 수치형 타입( DOUBLE > FLOAT )
- 정확한 수치형 타입( NUMERIC > BIGINT > INT > SHORT )
- 문자열 타입( CHAR > VARCHAR )
비교 연산¶
다음은 비교 연산자의 피연산자 타입에 따른 변환 규칙이다.
operand1 타입 | operand2 타입 | 변환 | 비교 타입 |
---|---|---|---|
수치형 타입 | 수치형 타입 | 없음 | NUMERIC |
문자열 타입 | operand2를 DOUBLE 로 변환 | NUMERIC | |
날짜/시간 타입 | operand1을 날짜/시간으로 변환 | TIME/TIMESTAMP | |
문자열 타입 | 수치형 타입 | operand1을 DOUBLE 로 변환 | NUMERIC |
문자열 타입 | 없음 | 문자열 | |
날짜/시간 타입 | operand1을 날짜/시간 타입으로 변환 | 날짜/시간 | |
날짜/시간 타입 | 수치형 타입 | operand2를 날짜/시간으로 변환 | TIME/TIMESTAMP |
문자열 타입 | operand2를 날짜/시간 타입으로 변환 | 날짜/시간 | |
날짜/시간 타입 | 우선순위가 높은 타입으로 변환 | 날짜/시간 |
날짜/시간 타입과 수치형 타입이 비교되는 경우 위 표의 숫자가 TIME 또는 TIMESTAMP로 변환될 때 제약 조건을 참고한다.
operand1이 문자열 타입의 칼럼이고 operand2가 값인 경우, 다음과 같은 예외가 있다.
operand1 타입 | operand2 타입 | 변환 | 비교 |
---|---|---|---|
문자열 타입의 칼럼 | 수치형 타입 값 | operand2를 문자열 타입으로 변환 | 문자열 |
날짜/시간 타입 값 | operand2를 문자열 타입으로 변환 | 문자열 |
operand2가 집합인 연산자( IS IN, IS NOT IN, = ALL, = ANY, < ALL, < ANY, <= ALL, <= ANY, >= ALL, >= ANY )에 대해서는 위의 예외가 적용되지 않는다.
다음은 비교 연산에서 묵시적 타입 변환의 예이다.
수치형 타입과 문자열 타입 피연산자
문자열 타입 피연산자가 DOUBLE 로 변환된다.
CREATE TABLE t1(i INT, s STRING); INSERT INTO t1 VALUES(1,'1'),(2,'2'),(3,'3'),(4,'4'), (12,'12'); SELECT i FROM t1 WHERE i < '11.3';
i ============= 1 2 3 4
SELECT ('2' <= 11);
('2'<=11) ============= 1
문자열 타입과 날짜/시간 타입 피연산자
문자열 타입 피연산자가 날짜/시간 타입으로 변환된다.
SELECT ('2010-01-01' < date'2010-02-02');
('2010-01-01'<date '2010-02-02') ================================== 1
SELECT (date'2010-02-02' >= '2010-01-01');
(date '2010-02-02'>='2010-01-01') =================================== 1
문자열 타입과 수치형 타입 호스트 변수 피연산자
수치형 타입 호스트 변수가 문자열 타입으로 변환된다.
PREPARE s FROM 'SELECT s FROM t1 WHERE s < ?'; EXECUTE s USING 11;
s =================== '1'
문자열 타입 칼럼과 수치형 타입 값 피연산자
수치형 타입 값이 문자열 타입으로 변환된다.
SELECT s FROM t1 WHERE s > 11;
s ================== '2' '3' '4' '12'
SELECT s FROM t1 WHERE s BETWEEN 11 AND 33;
s ====================== '2' '3' '12'
문자열 타입 칼럼과 날짜/시간 타입 값 피연산자
날짜/시간 타입 값이 문자열 타입으로 변환된다.
CREATE TABLE t2 (s STRING); INSERT INTO t2 VALUES ('01/01/1998'), ('01/01/1999'), ('01/01/2000'); SELECT s FROM t2;
s ====================== '01/01/1998' '01/01/1999' '01/01/2000'
SELECT s FROM t2 WHERE s <= date'02/02/1998';
위의 질의에서 date'02/02/1998'이 문자열 '02/02/1998'으로 변환되어 문자열 간의 비교 연산이 수행된다.
s ====================== '01/01/1998' '01/01/1999' '01/01/2000'
범위 연산¶
수치형 타입과 문자열 타입 피연산자
문자열 타입 피연산자가 DOUBLE 로 변환된다.
CREATE TABLE t3 (i INT); INSERT INTO t3 VALUES (1), (2), (3), (4); SELECT i FROM t3 WHERE i <= ALL {'11','12'};
i ============= 1 2 3 4
문자열 타입과 날짜/시간 타입 피연산자
문자열 타입 피연산자가 날짜/시간 타입으로 변환된다.
SELECT s FROM t2;
s ================= '01/01/1998' '01/01/1999' '01/01/2000'
SELECT s FROM t2 WHERE s <= ALL {date'02/02/1998',date'01/01/2000'};
s ================ '01/01/1998'
해당 타입으로 변환할 수 없으면 오류를 반환한다.
산술 연산¶
날짜/시간 타입 피연산자
날짜/시간 타입의 피연산자가 '-' 연산자에 주어지고 타입이 서로 다르면, 두 타입을 비교하여 우선순위가 높은 쪽의 타입으로 변환된다. 다음 예는 왼쪽 피연산자의 데이터 타입이 DATE 에서 DATETIME 으로 바뀌어 결과는 DATETIME 의 '-' 연산 결과인 밀리초를 출력한다.
SELECT date'2002-01-01' - datetime'2001-02-02 12:00:00 am';
date '2002-01-01'- datetime '2001-02-02 12:00:00 am' ===================================================== 28771200000
수치형 타입 피연산자
수치형 타입의 피연산자가 주어지고 타입이 서로 다르면, 두 타입을 비교하여 우선순위가 높은 쪽의 타입으로 변환된다.
날짜/시간 타입과 수치형 타입 피연산자
날짜/시간 타입과 수치형 타입의 피연산자가 '+' 또는 '-' 연산자에 주어지면, 수치형 타입 피연산자는 BIGINT, INT, SHORT 중 하나로 변환된다.
날짜/시간 타입과 문자열 타입 피연산자
날짜/시간 타입과 문자열 타입이 피연산자이면, '+'와 '-' 연산자만 허용한다. '+' 연산자가 사용되면 다음 규칙이 적용된다.
- 문자열 타입은 인터벌(interval) 값을 지닌 BIGINT 로 변환된다. 인터벌은 날짜/시간 타입 피연산자의 가장 작은 단위를 의미하며, 각 타입의 인터벌 값은 다음과 같다. * DATE : 일수(days) * TIME, TIMESTAMP : 초수(seconds) * DATETIME : 밀리초수(milliseconds)
- 부동소수점수는 반올림된다.
- 결과 타입은 날짜/시간 타입 피연산자의 타입이다.
SELECT date'2002-01-01' + '10';
date '2002-01-01'+'10' ====================== 01/11/2002
날짜/시간 타입과 문자열 타입이 피연산자이고, '-' 연산자가 사용되면 다음 규칙이 적용된다.
- 날짜/시간 타입 피연산자가 DATE, DATETIME, TIMESTAMP 이면 문자열은 DATETIME 으로 변환되고, 날짜/시간 타입 피연산자가 TIME 이면 문자열은 TIME 으로 변환된다.
- 결과 타입은 항상 BIGINT 이다.
SELECT date'2002-01-01'-'2001-01-01';
date '2002-01-01'-'2001-01-01' ================================ 31536000000 -- this causes an error
SELECT date'2002-01-01'-'10';
ERROR: Cannot coerce '10' to type datetime.
수치형 타입과 문자열 타입 피연산자
수치형 타입과 문자열 타입이 피연산자이면 다음 규칙이 적용된다.
- 문자열은 가능하면 DOUBLE로 변환된다.
- 결과 타입은 DOUBLE이며, 수치형 피연산자의 타입에 따라 결정된다.
SELECT 4 + '5.2';
4+'5.2' ========================== 9.199999999999999e+00
CUBRID 2008 R3.1 이하 버전과 달리, 날짜/시간 형태의 문자열, 즉 '2010-09-15'와 같은 문자열은 날짜/시간 타입으로 변환되지 않는다. 날짜/시간 타입을 갖는 리터럴 (date'2010-09-15')은 덧셈, 뺄셈 연산에 사용할 수 있다.
SELECT '2002-01-01'+1;
ERROR: Cannot coerce '2002-01-01' to type double.
SELECT date'2002-01-01'+1;
date '2002-01-01'+1 ===================== 01/02/2002
문자열 타입 피연산자
두 문자열을 곱하거나 나누거나 빼면 숫자로 변환되며, 결과로 DOUBLE 타입의 값을 반환한다.
SELECT '3'*'2';
'3'*'2' ============================ 6.000000000000000e+00
'+' 연산자의 동작은 cubrid.conf 의 시스템 파라미터인 plus_as_concat을 어떻게 설정하느냐에 따라 결정된다. 자세한 내용은 구문/타입 관련 파라미터를 참고한다.
plus_as_concat 값이 yes(기본값)이면 두 개의 문자열을 연결한 값을 반환한다.
SELECT '1'+'1';
'1'+'1' ====================== '11'
plus_as_concat 값이 no이고 두 개의 문자열이 숫자로 변환 가능하면, 두 숫자를 더하여 DOUBLE 타입의 값을 반환한다.
SELECT '1'+'1';
'1'+'1' ========================== 2.000000000000000e+00
해당 타입으로 변환할 수 없으면 오류를 반환한다.